package Planificador.test;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;

import Planificador.core.Registro;
import Planificador.core.SistemaOperativo;
import Planificador.core.algoritmos.AlgoritmoPrioridadesConDesalojo;
import Planificador.core.algoritmos.AlgoritmoPrioridadesSinDesalojo;
import Planificador.core.algoritmos.AlgoritmoRoundRobin;
import Planificador.core.algoritmos.AlgoritmoSPNconDesalojo;
import Planificador.core.algoritmos.AlgoritmoSPNsinDesalojo;
import Planificador.core.dispositivos.DispositivoExterno;
import Planificador.core.dispositivos.Procesador;
import Planificador.core.exceptions.NoRegistroException;
import Planificador.core.proceso.InstruccionPedidoEntradaSalida;
import Planificador.core.proceso.InstruccionUsoCpu;
import Planificador.core.proceso.Proceso;

public class testSistemaOperativo {

	SistemaOperativo sistemaOperativo;

	@Before
	public void fixture() {
		this.sistemaOperativo = new SistemaOperativo();

	}

	@Test
	public void testTrivial() throws NoRegistroException {
		Proceso p1 = new Proceso("p1", 2);
		Proceso p2 = new Proceso("p2", 3);

		Procesador p = sistemaOperativo.getProcesador();

		DispositivoExterno disco = sistemaOperativo
				.agregarDispositivoExterno("disco");

		p1.addInstruccion(new InstruccionUsoCpu(2, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(3, disco));
		p1.addInstruccion(new InstruccionUsoCpu(1, p));

		p2.addInstruccion(new InstruccionUsoCpu(2, p));
		p2.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p2.addInstruccion(new InstruccionUsoCpu(1, p));

		sistemaOperativo.agregarProceso(p1);
		sistemaOperativo.agregarProceso(p2);

		sistemaOperativo.correrEjercicio();

		Assert.assertEquals("[[2, , nuevos, p1], [2, nuevos, listos, p1], [2, listos, procesador, p1], [3, , nuevos, p2], [3, nuevos, listos, p2], [4, procesador, cola ES disco, p1], [4, listos, procesador, p2], [4, cola ES disco, dispositivo disco, p1], [6, procesador, cola ES disco, p2], [7, E/S disco, listos, p1], [7, listos, procesador, p1], [7, cola ES disco, dispositivo disco, p2], [8, procesador, , p1], [9, E/S disco, listos, p2], [9, listos, procesador, p2], [10, procesador, , p2]]",Registro.getSucesos().toString());

	}

	@Test
	public void test1FIFO() throws NoRegistroException {
		Procesador p = sistemaOperativo.getProcesador();

		Proceso p1 = new Proceso("p1", 0);
		Proceso p2 = new Proceso("p2", 1);
		Proceso p3 = new Proceso("p3", 4);

		DispositivoExterno disco = sistemaOperativo
				.agregarDispositivoExterno("disco");

		p1.addInstruccion(new InstruccionUsoCpu(3, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(1, disco));
		p1.addInstruccion(new InstruccionUsoCpu(3, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(5, disco));
		p1.addInstruccion(new InstruccionUsoCpu(2, p));

		p2.addInstruccion(new InstruccionUsoCpu(1, p));
		p2.addInstruccion(new InstruccionPedidoEntradaSalida(5, disco));
		p2.addInstruccion(new InstruccionUsoCpu(4, p));

		p3.addInstruccion(new InstruccionUsoCpu(3, p));
		p3.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p3.addInstruccion(new InstruccionUsoCpu(2, p));
		p3.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p3.addInstruccion(new InstruccionUsoCpu(5, p));

		sistemaOperativo.agregarProceso(p1);
		sistemaOperativo.agregarProceso(p2);
		sistemaOperativo.agregarProceso(p3);

		sistemaOperativo.correrEjercicio();

		Assert
				.assertEquals(
						"[[0, , nuevos, p1], [0, nuevos, listos, p1], [0, listos, procesador, p1], [1, , nuevos, p2], [1, nuevos, listos, p2], [3, procesador, cola ES disco, p1], [3, listos, procesador, p2], [3, cola ES disco, dispositivo disco, p1], [4, E/S disco, listos, p1], [4, , nuevos, p3], [4, nuevos, listos, p3], [4, procesador, cola ES disco, p2], [4, listos, procesador, p1], [4, cola ES disco, dispositivo disco, p2], [7, procesador, cola ES disco, p1], [7, listos, procesador, p3], [9, E/S disco, listos, p2], [9, cola ES disco, dispositivo disco, p1], [10, procesador, cola ES disco, p3], [10, listos, procesador, p2], [14, E/S disco, listos, p1], [14, procesador, , p2], [14, listos, procesador, p1], [14, cola ES disco, dispositivo disco, p3], [16, E/S disco, listos, p3], [16, procesador, , p1], [16, listos, procesador, p3], [18, procesador, cola ES disco, p3], [18, cola ES disco, dispositivo disco, p3], [20, E/S disco, listos, p3], [20, listos, procesador, p3], [25, procesador, , p3]]",
						Registro.getSucesos().toString());

	}

	@Test
	public void test2SPN() throws NoRegistroException {

		sistemaOperativo.setAlgoritmo(new AlgoritmoSPNsinDesalojo());

		Proceso p1 = new Proceso("p1", 2);
		Proceso p2 = new Proceso("p2", 0);
		Proceso p3 = new Proceso("p3", 1);

		Procesador p = sistemaOperativo.getProcesador();

		DispositivoExterno disco = sistemaOperativo
				.agregarDispositivoExterno("disco");

		p1.addInstruccion(new InstruccionUsoCpu(2, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(1, disco));
		p1.addInstruccion(new InstruccionUsoCpu(2, p));

		p2.addInstruccion(new InstruccionUsoCpu(4, p));
		p2.addInstruccion(new InstruccionPedidoEntradaSalida(5, disco));
		p2.addInstruccion(new InstruccionUsoCpu(5, p));

		p3.addInstruccion(new InstruccionUsoCpu(2, p));
		p3.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p3.addInstruccion(new InstruccionUsoCpu(3, p));

		sistemaOperativo.agregarProceso(p1);
		sistemaOperativo.agregarProceso(p2);
		sistemaOperativo.agregarProceso(p3);

		sistemaOperativo.correrEjercicio();

		Assert
				.assertEquals(
						"[[0, , nuevos, p2], [0, nuevos, listos, p2], [0, listos, procesador, p2], [1, , nuevos, p3], [1, nuevos, listos, p3], [2, , nuevos, p1], [2, nuevos, listos, p1], [4, procesador, cola ES disco, p2], [4, listos, procesador, p3], [4, cola ES disco, dispositivo disco, p2], [6, procesador, cola ES disco, p3], [6, listos, procesador, p1], [8, procesador, cola ES disco, p1], [9, E/S disco, listos, p2], [9, listos, procesador, p2], [9, cola ES disco, dispositivo disco, p3], [11, E/S disco, listos, p3], [11, cola ES disco, dispositivo disco, p1], [12, E/S disco, listos, p1], [14, procesador, , p2], [14, listos, procesador, p1], [16, procesador, , p1], [16, listos, procesador, p3], [19, procesador, , p3]]",
						Registro.getSucesos().toString());

	}

	@Test
	public void test3PrioridadesSinDesalojo() throws NoRegistroException {

		sistemaOperativo.setAlgoritmo(new AlgoritmoPrioridadesSinDesalojo());

		Proceso p1 = new Proceso("A", 0, 2);
		Proceso p2 = new Proceso("B", 1, 1);
		Proceso p3 = new Proceso("C", 3, 4);
		Proceso p4 = new Proceso("D", 9, 5);
		Proceso p5 = new Proceso("E", 12, 3);

		Procesador p = sistemaOperativo.getProcesador();

		p1.addInstruccion(new InstruccionUsoCpu(3, p));
		p2.addInstruccion(new InstruccionUsoCpu(1, p));
		p3.addInstruccion(new InstruccionUsoCpu(12, p));
		p4.addInstruccion(new InstruccionUsoCpu(5, p));
		p5.addInstruccion(new InstruccionUsoCpu(5, p));

		sistemaOperativo.agregarProceso(p1).agregarProceso(p2).agregarProceso(
				p3).agregarProceso(p4).agregarProceso(p5);

		sistemaOperativo.correrEjercicio();

		Assert
				.assertEquals(
						"[[0, , nuevos, A], [0, nuevos, listos, A], [0, listos, procesador, A], [1, , nuevos, B], [1, nuevos, listos, B], [3, , nuevos, C], [3, nuevos, listos, C], [3, procesador, , A], [3, listos, procesador, B], [4, procesador, , B], [4, listos, procesador, C], [9, , nuevos, D], [9, nuevos, listos, D], [12, , nuevos, E], [12, nuevos, listos, E], [16, procesador, , C], [16, listos, procesador, E], [21, procesador, , E], [21, listos, procesador, D], [26, procesador, , D]]",
						Registro.getSucesos().toString());
	}

	@Test
	public void test4SPNconDesalojo() throws NoRegistroException {

		sistemaOperativo.setAlgoritmo(new AlgoritmoSPNconDesalojo());

		Proceso p1 = new Proceso("A", 2);
		Proceso p2 = new Proceso("B", 0);
		Proceso p3 = new Proceso("C", 1);

		Procesador p = sistemaOperativo.getProcesador();

		DispositivoExterno disco = sistemaOperativo
				.agregarDispositivoExterno("disco");

		p1.addInstruccion(new InstruccionUsoCpu(2, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(1, disco));
		p1.addInstruccion(new InstruccionUsoCpu(2, p));

		p2.addInstruccion(new InstruccionUsoCpu(4, p));
		p2.addInstruccion(new InstruccionPedidoEntradaSalida(5, disco));
		p2.addInstruccion(new InstruccionUsoCpu(5, p));

		p3.addInstruccion(new InstruccionUsoCpu(2, p));
		p3.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p3.addInstruccion(new InstruccionUsoCpu(3, p));

		sistemaOperativo.agregarProceso(p1);
		sistemaOperativo.agregarProceso(p2);
		sistemaOperativo.agregarProceso(p3);

		sistemaOperativo.correrEjercicio();

		Assert
				.assertEquals(
						"[[0, , nuevos, B], [0, nuevos, listos, B], [0, listos, procesador, B], [1, , nuevos, C], [1, nuevos, listos, C], [1, procesador, listos, B], [1, listos, procesador, C], [2, , nuevos, A], [2, nuevos, listos, A], [3, procesador, cola ES disco, C], [3, listos, procesador, A], [3, cola ES disco, dispositivo disco, C], [5, E/S disco, listos, C], [5, procesador, cola ES disco, A], [5, listos, procesador, B], [5, cola ES disco, dispositivo disco, A], [6, E/S disco, listos, A], [8, procesador, cola ES disco, B], [8, listos, procesador, A], [8, cola ES disco, dispositivo disco, B], [10, procesador, , A], [10, listos, procesador, C], [13, E/S disco, listos, B], [13, procesador, , C], [13, listos, procesador, B], [18, procesador, , B]]",
						Registro.getSucesos().toString());

	}

	@Test
	public void testSPNconDesalojoAuxiliar() throws NoRegistroException {

		sistemaOperativo.setAlgoritmo(new AlgoritmoSPNconDesalojo());

		Proceso p1 = new Proceso("A", 0);
		Proceso p2 = new Proceso("B", 0);
		Proceso p3 = new Proceso("C", 2);

		Procesador p = sistemaOperativo.getProcesador();

		DispositivoExterno disco = sistemaOperativo
				.agregarDispositivoExterno("disco");

		p1.addInstruccion(new InstruccionUsoCpu(1, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(1, disco));
		p1.addInstruccion(new InstruccionUsoCpu(1, p));

		p2.addInstruccion(new InstruccionUsoCpu(10, p));

		p3.addInstruccion(new InstruccionUsoCpu(2, p));

		sistemaOperativo.agregarProceso(p1);
		sistemaOperativo.agregarProceso(p2);
		sistemaOperativo.agregarProceso(p3);

		sistemaOperativo.correrEjercicio();

		// System.out.print(Registro.getSucesos().toString());

	}

	@Test
	public void testPrioridadesConDesalojo() throws NoRegistroException {

		sistemaOperativo.setAlgoritmo(new AlgoritmoPrioridadesConDesalojo());

		Proceso p1 = new Proceso("A", 1, 1);
		Proceso p2 = new Proceso("B", 1, 2);
		Proceso p3 = new Proceso("C", 0, 2);

		Procesador p = sistemaOperativo.getProcesador();

		DispositivoExterno disco = sistemaOperativo
				.agregarDispositivoExterno("disco");

		p1.addInstruccion(new InstruccionUsoCpu(2, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(1, disco));
		p1.addInstruccion(new InstruccionUsoCpu(5, p));

		p2.addInstruccion(new InstruccionUsoCpu(10, p));
		p2.addInstruccion(new InstruccionPedidoEntradaSalida(5, disco));
		p2.addInstruccion(new InstruccionUsoCpu(5, p));

		p3.addInstruccion(new InstruccionUsoCpu(2, p));
		p3.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p3.addInstruccion(new InstruccionUsoCpu(3, p));

		sistemaOperativo.agregarProceso(p1);
		sistemaOperativo.agregarProceso(p2);
		sistemaOperativo.agregarProceso(p3);

		sistemaOperativo.correrEjercicio();

		Assert
				.assertEquals(
						"[[0, , nuevos, C], [0, nuevos, listos, C], [0, listos, procesador, C], [1, , nuevos, A], [1, nuevos, listos, A], [1, , nuevos, B], [1, nuevos, listos, B], [1, procesador, listos, C], [1, listos, procesador, A], [3, procesador, cola ES disco, A], [3, listos, procesador, B], [3, cola ES disco, dispositivo disco, A], [4, E/S disco, listos, A], [4, procesador, listos, B], [4, listos, procesador, A], [9, procesador, , A], [9, listos, procesador, C], [10, procesador, cola ES disco, C], [10, listos, procesador, B], [10, cola ES disco, dispositivo disco, C], [12, E/S disco, listos, C], [19, procesador, cola ES disco, B], [19, listos, procesador, C], [19, cola ES disco, dispositivo disco, B], [22, procesador, , C], [24, E/S disco, listos, B], [24, listos, procesador, B], [29, procesador, , B]]",
						Registro.getSucesos().toString());

	}

	@Test
	public void testRoundRobin() throws NoRegistroException {

		sistemaOperativo.setAlgoritmo(new AlgoritmoRoundRobin(3));

		Proceso p1 = new Proceso("A", 0);
		Proceso p2 = new Proceso("B", 0);
		Proceso p3 = new Proceso("C", 6);
		Proceso p4 = new Proceso("D", 7);

		Procesador p = sistemaOperativo.getProcesador();

		DispositivoExterno disco = sistemaOperativo
				.agregarDispositivoExterno("disco");

		p1.addInstruccion(new InstruccionUsoCpu(3, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(3, disco));
		p1.addInstruccion(new InstruccionUsoCpu(4, p));
		p1.addInstruccion(new InstruccionPedidoEntradaSalida(6, disco));
		p1.addInstruccion(new InstruccionUsoCpu(3, p));

		p2.addInstruccion(new InstruccionUsoCpu(4, p));
		p2.addInstruccion(new InstruccionPedidoEntradaSalida(3, disco));
		p2.addInstruccion(new InstruccionUsoCpu(3, p));
		p2.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p2.addInstruccion(new InstruccionUsoCpu(5, p));

		p3.addInstruccion(new InstruccionUsoCpu(5, p));
		p3.addInstruccion(new InstruccionPedidoEntradaSalida(2, disco));
		p3.addInstruccion(new InstruccionUsoCpu(2, p));
		p3.addInstruccion(new InstruccionPedidoEntradaSalida(3, disco));
		p3.addInstruccion(new InstruccionUsoCpu(2, p));

		p4.addInstruccion(new InstruccionUsoCpu(2, p));
		p4.addInstruccion(new InstruccionPedidoEntradaSalida(4, disco));
		p4.addInstruccion(new InstruccionUsoCpu(5, p));
		p4.addInstruccion(new InstruccionPedidoEntradaSalida(4, disco));
		p4.addInstruccion(new InstruccionUsoCpu(4, p));

		sistemaOperativo.agregarProceso(p1);
		sistemaOperativo.agregarProceso(p2);
		sistemaOperativo.agregarProceso(p3);
		sistemaOperativo.agregarProceso(p4);

		sistemaOperativo.correrEjercicio();

		System.out.print(Registro.getSucesos().toString());

	}

}
